﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Packaging;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Practices.Composite.Events;
using ShellLight.Contract;
using ShellLight.Contract.Attributes;
using ShellLight.ViewModels;
using ShellLight.Views;

namespace ShellLight
{
    public partial class MainPage : UserControl
    {
        [ImportMany(AllowRecomposition = true)]
        public ObservableCollection<UICommand> RegisteredCommands { get; set; }

        private IEventAggregator events;
        private SearchWindow searchWindow;
        private Stack<Uri> packagesToDownload;
        int numberOfRetriesWhenPackageDownloadFails = Config.NumberOfRetriesWhenPackageDownloadFails;

        public MainPage()
        {
            InitializeComponent();

            DataContext = new MainPageViewModel();
            events = new EventAggregator();

            packagesToDownload = new Stack<Uri>(Config.ModuleUris);
           
            // Create a catalog and add this XAP to it
            PackageCatalog catalog = new PackageCatalog();
            catalog.AddPackage(Package.Current);

            DowloadPackagesAsync(catalog);

            // Pass the catalog to the MEF and compose the parts
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
    
            this.KeyDown += MainPage_KeyDown;
        }

        private void DowloadPackagesAsync(PackageCatalog catalog)
        {
            if (packagesToDownload.Count > 0) 
             {
                Package.DownloadPackageAsync(packagesToDownload.Peek(), (s, p) =>
                                                      {
                                                          var pUri = packagesToDownload.Pop();
                                                          if (!s.Cancelled && (s.Error == null))
                                                          {
                                                              catalog.AddPackage(p);
                                                              InitializeCommands();
                                                              DowloadPackagesAsync(catalog);
                                                          } else
                                                          {
                                                              if (numberOfRetriesWhenPackageDownloadFails > 0)
                                                              {
                                                                  --numberOfRetriesWhenPackageDownloadFails;
                                                                  packagesToDownload.Push(pUri);
                                                              }
                                                              else
                                                              {
                                                                 var message =
                                                                      string.Format("could not load module {0} after {1} retries.\n\n" +
                                                                                    "If you are a developer please ensure that ShellLight.Web is your startup project",
                                                                                    pUri.ToString(),Config.NumberOfRetriesWhenPackageDownloadFails);
                                                                  ViewHelper.ShowError(message,"Could not load module");
                                                              }
                                                              DowloadPackagesAsync(catalog);
                                                          }
                                                      });
            }
        }

        private void InitializeCommands()
        {
            foreach (var command in RegisteredCommands.Where(c => c.State == UICommandState.Created))
            {
                AttachScore(command);
                RegisterCommandEvents(command);
                SetupBehaviorBasedOnAttributes(command);

                command.State = UICommandState.Initialized;
            }
        }

        private void SetupBehaviorBasedOnAttributes(UICommand command)
        {
            if (command.HasAttribute<AttachToTrayAttribute>())
            {
                //MessageBox.Show("attach to tray " + command.Name);
                var context = new UICommandContext() { Events = events, RegiseredCommands = RegisteredCommands.ToList() };
                command.Execute(context);
            }
        }

        private void RegisterCommandEvents(UICommand command)
        {
            command.BeforeShow += command_BeforeShow;
            command.AfterShow += command_AfterShow;
        }

        private void AttachScore(UICommand command)
        {
            if (IsolatedStorageSettings.ApplicationSettings.Contains(command.Id))
            {
                command.Score = (int)IsolatedStorageSettings.ApplicationSettings[command.Id];
                //MessageBox.Show(command.Name + "->" + command.Score.ToString());
            }
        }

        private void IncrementScore(UICommand command)
        {
            var score = 1;
            if (IsolatedStorageSettings.ApplicationSettings.Contains(command.Id))
            {
                score = (int)IsolatedStorageSettings.ApplicationSettings[command.Id] + 1;
            }
            //MessageBox.Show("issolated storage update hits " + score);
            IsolatedStorageSettings.ApplicationSettings[command.Id] = score;
        }

        void command_BeforeShow(object sender, EventArgs e)
        {
            if (searchWindow != null)
            {
                searchWindow.Close();
            }
        }

        void command_AfterShow(object sender, UICommandEventArgs e)
        {
            var datacontext = DataContext as MainPageViewModel;
            var command = sender as UICommand;

            if (command != null)
                IncrementScore(command);
            if (command.IsModal)
            {
                var modalWindow = new ModalWindow(command.View, command.Name);
                modalWindow.Show();
            }
            else if (command.View != null)
            {
                if (command.HasAttribute<AttachToTrayAttribute>())
                {
                    if (!datacontext.TrayCommands.Contains(command))
                    {
                        datacontext.TrayCommands.Add(command);
                    }
                    else
                    {
                        var trayWindow = new TrayWindow(command.View, command.Name);
                        trayWindow.Show();
                    }
                }
                else
                {
                    datacontext.CommandInFocus = command;

                    if (!datacontext.ActiveCommands.Contains(command))
                    {
                        datacontext.ActiveCommands.Add(command);
                    }
                }
            }

        }

        void MainPage_KeyDown(object sender, KeyEventArgs e)
        {
            if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.F)
            {
                OpenSearchWindow();
            }
        }

        private void SearchButton_Click(object sender, RoutedEventArgs e)
        {
            OpenSearchWindow();
        }

        private void OpenSearchWindow()
        {
            searchWindow = new SearchWindow(RegisteredCommands, events);
            searchWindow.VerticalAlignment = VerticalAlignment.Bottom;
            searchWindow.HorizontalAlignment = HorizontalAlignment.Left;
            searchWindow.Show();
        }

        private void CloseCommandButton_Click(object sender, RoutedEventArgs e)
        {
            var datacontext = DataContext as MainPageViewModel;
            if (datacontext.CommandInFocus != null)
            {
                datacontext.ActiveCommands.Remove(datacontext.CommandInFocus);
                datacontext.CommandInFocus = null;
            }
        }
    }
}
